#include "netcfgapplet.h"
#include "netcfginterface.h"
#include "../netcfgactions.h"

#include <QPainter>
#include <QTreeView>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QHeaderView>
#include <QGraphicsLinearLayout>
#include <QDBusConnection>
#include <QTimer>

#include <KIcon>
#include <KPushButton>

#include <Plasma/Extender>
#include <Plasma/ExtenderItem>
#include <Plasma/TreeView>
#include <Plasma/PushButton>
#include <Plasma/DataEngine>
#include <Plasma/DataContainer>
#include <Plasma/PushButton>
#include <PolicyKit/polkit-qt/Action>


class NetcfgAppletPrivate
{
    public:

        NetcfgApplet *q;
        KIcon icon;
        Plasma::PushButton *button;

        int activeProfilesCount;
        QStandardItemModel *model;
        QItemSelectionModel *selectionModel;
        QModelIndex lastSelectedIndex;

        OrgArchlinuxNetcfgInterface interface;
        PolkitQt::Action *actionUp;
        PolkitQt::Action *actionDown;
        PolkitQt::Action *actionAllDown;
        PolkitQt::Action *actionAutoWireless; 

        NetcfgAppletPrivate(NetcfgApplet *applet):
            q(applet),
            icon("applications-internet"),
            button(0),
            activeProfilesCount(0),
            model(0),
            interface("org.archlinux.netcfg", "/", QDBusConnection::systemBus()),
            actionUp(new PolkitQt::Action(NetcfgActionId::Up, applet)),
            actionDown(new PolkitQt::Action(NetcfgActionId::Down, applet)),
            actionAllDown(new PolkitQt::Action(NetcfgActionId::AllDown, applet)),
            actionAutoWireless(new PolkitQt::Action(NetcfgActionId::AutoWireless, applet))
        {
            actionUp->setText(i18n("Profile up"));
            QObject::connect(actionUp, SIGNAL(activated()), q, SLOT(slotUp()));

            actionDown->setText(i18n("Profile down"));
            QObject::connect(actionDown, SIGNAL(activated()), q, SLOT(slotDown()));

            actionAllDown->setText(i18n("All down"));
            QObject::connect(actionAllDown, SIGNAL(activated()), q, SLOT(slotAllDown()));

            actionAutoWireless->setText(i18n("Auto wireless"));
            QObject::connect(actionAutoWireless, SIGNAL(activated()), q, SLOT(slotAutoWireless()));
        }

        bool hilightWhenActive(QStandardItem *item)
        {
            bool isActive = q->dataEngine("netcfg")->query(item->text()).value("isActive").toBool();
            QFont font = item->font();
            if (!isActive) {
                font.setBold(false);
            } else {
                font.setBold(true);
            }
            item->setFont(font);
            item->setIcon(icon);
            return isActive;
        }

        void updateButton()
        { 
            QModelIndexList selectedIndexes = selectionModel->selectedIndexes();
            PolkitQt::Action *action;

            if (selectedIndexes.isEmpty()) {
                if (activeProfilesCount > 0) {
                    action = actionAllDown;
                } else {
                    action = actionAutoWireless;
                }
            } else {
                QStandardItem *item = model->itemFromIndex(selectedIndexes.first());
                bool isActive = q->dataEngine("netcfg")->query(item->text()).value("isActive").toBool();
                if (!isActive) {
                    action = actionUp;
                } else {
                    action = actionDown;
                }
            }

            // use Plasma::PushButton::setAction in KDE>=4.3
            QObject::disconnect(button, SIGNAL(clicked()), 0, 0);
            QObject::connect(button, SIGNAL(clicked()), action, SLOT(activate()));
            button->setText(action->text());
        }
};

// public

NetcfgApplet::NetcfgApplet(QObject *parent, const QVariantList &args) :
    Plasma::PopupApplet(parent, args),
    d(new NetcfgAppletPrivate(this))
{
}

void NetcfgApplet::init()
{
    if (!extender()->hasItem("netcfg")) {
        Plasma::ExtenderItem *item = new Plasma::ExtenderItem(extender());
        item->setName("netcfg");
        initExtenderItem(item);
    };
}

// protected

void NetcfgApplet::paintInterface(QPainter *painter,
    const QStyleOptionGraphicsItem *option,
    const QRect &contentsRect)
{
    Q_UNUSED(option);

    KIcon::Mode iconMode;
    if (d->activeProfilesCount > 0) {
        iconMode = KIcon::Normal;
    } else {
        iconMode = KIcon::Disabled;
    }
    QPixmap pixmap = d->icon.pixmap(contentsRect.size(), iconMode);
    painter->drawPixmap(contentsRect, pixmap);
}

void NetcfgApplet::initExtenderItem(Plasma::ExtenderItem *item)
{
    QGraphicsWidget *widget = new QGraphicsWidget(item);
    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, widget);
    widget->setLayout(layout);    

    // initialize the treeview widget and its model
    d->model = new QStandardItemModel(item);
    Plasma::TreeView *treeview = new Plasma::TreeView(item);
    treeview->setModel(d->model);
    d->selectionModel = treeview->nativeWidget()->selectionModel();
    treeview->nativeWidget()->header()->hide();
    treeview->nativeWidget()->setRootIsDecorated(false);
    connect(treeview->nativeWidget(), SIGNAL(activated(const QModelIndex &)), this, SLOT(slotActivated(const QModelIndex &)));
    connect(dataEngine("netcfg"), SIGNAL(profilesChanged()), this, SLOT(slotProfilesUpdate()));
    connect(dataEngine("netcfg"), SIGNAL(stateChanged()), this, SLOT(slotStateUpdate()));
    slotProfilesUpdate();
    layout->addItem(treeview);
    
    // initialize the button container widget
    QGraphicsWidget *buttonsWidget = new QGraphicsWidget(item);
    QGraphicsLinearLayout *buttonsLayout = new QGraphicsLinearLayout(Qt::Horizontal, buttonsWidget);
    buttonsWidget->setLayout(buttonsLayout); 
    d->button = new Plasma::PushButton(item);
    d->updateButton();
    buttonsLayout->addItem(d->button);
    layout->addItem(buttonsWidget); 

    item->setTitle(i18n("netcfg"));
    item->setWidget(widget); // must be done after widget is filled
}

// private slots

void NetcfgApplet::slotUp()
{
    setBusy(true);
    QString profile = d->model->itemFromIndex(d->lastSelectedIndex)->text();
    QDBusPendingCall call = d->interface.up(profile);
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(slotFinished(QDBusPendingCallWatcher *)));
    hidePopup();
}

void NetcfgApplet::slotDown()
{
    setBusy(true);
    QString profile = d->model->itemFromIndex(d->lastSelectedIndex)->text();
    QDBusPendingCall call = d->interface.down(profile);
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(slotFinished(QDBusPendingCallWatcher *)));
    hidePopup();
}

void NetcfgApplet::slotAllDown()
{
    setBusy(true);
    QDBusPendingCall call = d->interface.allDown();
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(slotFinished(QDBusPendingCallWatcher *)));
    hidePopup();
}

void NetcfgApplet::slotAutoWireless()
{
    setBusy(true);
    QDBusPendingCall call = d->interface.autoWireless(); 
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(slotFinished(QDBusPendingCallWatcher *)));
    hidePopup();
}

void NetcfgApplet::slotFinished(QDBusPendingCallWatcher *watcher)
{
    setBusy(false);
    delete watcher;
}

void NetcfgApplet::slotActivated(const QModelIndex &index)
{
    // custom toggle selection built on top of QAbstractItemView::SingleSelection
    if (d->lastSelectedIndex == index) {
        d->selectionModel->select(index, QItemSelectionModel::Clear);
        d->lastSelectedIndex = QModelIndex(); // invalid model index
    } else {
        d->lastSelectedIndex = index;
    }
    d->updateButton();
}

void NetcfgApplet::slotProfilesUpdate()
{
    d->model->removeRows(0, d->model->rowCount());
    QStringListIterator iterator(dataEngine("netcfg")->sources());
    QStandardItem *item;
    int activeProfilesCount = 0;

    while (iterator.hasNext()) {
        // XXX leaking
        item = new QStandardItem(iterator.next());
        if (d->hilightWhenActive(item)) {
            activeProfilesCount += 1;
        }
        item->setEditable(false);
        d->model->appendRow(item);
    }

    d->activeProfilesCount = activeProfilesCount;
    update();
}

void NetcfgApplet::slotStateUpdate()
{
    int rowCount = d->model->rowCount();
    QStandardItem *item;
    int activeProfilesCount = 0;

    for (int i = 0; i < rowCount; i++) {
        item = d->model->itemFromIndex(d->model->index(i, 0));
        if (d->hilightWhenActive(item)) {
            activeProfilesCount += 1;    
        }
    }

    d->activeProfilesCount = activeProfilesCount;
    d->updateButton();
    update();
}


#include "netcfgapplet.moc"
